﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace HttpTest
{
    public class Http_Tool
    {
        public static readonly Http_Tool Ins = new Http_Tool();

        /// <summary>
        /// 使用Http协议，向服务端发起请求，并获取返回值。支持Get、Post方法。
        /// </summary>
        /// <param name="uri">请求服务器的路径</param>
        /// <param name="method">请求方式</param>
        /// <param name="head_lines">标头</param>
        /// <param name="data">发送的数据</param>
        /// <returns></returns>
        public string Request(string uri,string method,string head_lines,string data)
        {
            var heads = head_lines.Replace("\r\n", "\n").Split('\n').ToList();
            return Request(uri, method, heads, data);
        }

        public string Request(string uri, string method, List<string> heads, string data)
        {
            if (string.IsNullOrEmpty(uri) || string.IsNullOrEmpty(method) || (method.ToLower() != "get" && method.ToLower() != "post"))
                return null;

            HttpWebRequest web = HttpWebRequest.Create(uri) as HttpWebRequest;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            //1. web.Headers 被更新为: heads
            Init_header();

            //2. Method:
            web.Method = method.ToUpper();
            byte[] send_data = string.IsNullOrEmpty(data) ? null : Encoding.UTF8.GetBytes(data);

            //3.send data
            if(send_data != null && send_data.Length >0)
            {
                SetHeaderValue(web.Headers, "Content-Length", send_data.Length.ToString());
                using(var stream = web.GetRequestStream())
                {
                    stream.Write(send_data, 0, send_data.Length);
                }
            }
            //4. recv data
            HttpWebResponse response = (HttpWebResponse)web.GetResponse();

            //5.recv header
            string repon_heads = Get_header_lines(response.Headers);

            //6.return recv str
            string rtVal = "";
            Stream stm = response.GetResponseStream();
            if (!string.IsNullOrEmpty(response.ContentEncoding) && response.ContentEncoding.ToUpper().IndexOf("GZIP") > -1)
                stm = new GZipStream(stm, CompressionMode.Decompress);

            using (var sr = new StreamReader(stm, Encoding.UTF8))
                rtVal += sr.ReadToEnd();
            rtVal = repon_heads + "\r\n\r\n" + rtVal;
            return rtVal;

            void Init_header()
            {
                if (heads == null || heads.Count < 1) return;

                foreach(var head in heads)
                {
                    try
                    {
                        int start_pos = head.IndexOf(":");
                        if (start_pos < 0) return;

                        var key = head.Substring(0, start_pos).Trim();
                        var val = head.Substring(start_pos + 1).Trim();
                        if (key == "Content-Length" || key == "Connection") continue;

                        SetHeaderValue(web.Headers, key, val);

                      
                    }
                    catch { }
                }
            }

            string Get_header_lines(WebHeaderCollection header)
            {
                string str_val = "";
                foreach (var h in header)
                {
                    str_val = $"{str_val}{(string)h}: {header[(string)h]} \r\n";
                }
                return str_val;
            }
        }
        private void SetHeaderValue(WebHeaderCollection headers, string name, string val)
        {
            var property = typeof(WebHeaderCollection).GetProperty("InnerCollection", BindingFlags.Instance | BindingFlags.NonPublic);

            if(property != null)
            {
                var conlection = property.GetValue(headers, null) as NameValueCollection;
                conlection[name] = val;
            }    
        }


    }
}
